package com.valuegroup.smarttodo.data.service;

import android.os.Build;
import android.text.TextUtils;

import com.alibaba.fastjson.JSON;
import com.valuegroup.smarttodo.R;
import com.valuegroup.smarttodo.data.model.AppStatus;
import com.valuegroup.smarttodo.data.model.Habit;
import com.valuegroup.smarttodo.data.model.HabitDao;
import com.valuegroup.smarttodo.data.model.HabitEvent;
import com.valuegroup.smarttodo.data.model.HabitEventDao;
import com.valuegroup.smarttodo.data.model.HabitOrder;
import com.valuegroup.smarttodo.data.model.HabitOrderDao;
import com.valuegroup.smarttodo.data.model.HabitOrderRelate;
import com.valuegroup.smarttodo.data.model.HabitOrderRelateDao;
import com.valuegroup.smarttodo.data.model.Remark;
import com.valuegroup.smarttodo.data.model.RemarkDao;
import com.valuegroup.smarttodo.data.model.Task;
import com.valuegroup.smarttodo.data.vo.HabitAndOrderVo;
import com.valuegroup.smarttodo.data.vo.HabitItemVo;
import com.valuegroup.smarttodo.data.vo.HabitOrderVo;
import com.valuegroup.smarttodo.data.vo.HabitVo;
import com.valuegroup.smarttodo.plugins.pickdialog.DateUtils;

import org.greenrobot.greendao.query.QueryBuilder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;

import androidx.annotation.RequiresApi;

public class HabitService extends BaseService {
    private static final String TAG = HabitService.class.getSimpleName();

    private Random random = new Random();

    private static final Integer[] habitEmojiArray = new Integer[]{
            R.drawable.habit_love,
            R.drawable.habit_computer,
            R.drawable.habit_plan,
            R.drawable.habit_tag,
            R.drawable.habit_school,
            R.drawable.habit_drawing,
            R.drawable.habit_study,
            R.drawable.habit_drawing
    };

    public List<HabitAndOrderVo> findHabitAndGroupVo(boolean spHideFinish) {
        List<HabitAndOrderVo> result = new ArrayList<>();

        Map<Long, Habit> habitMap = findAllHabit2Map();
        List<HabitOrder> orders = findOrder();

        for (HabitOrder o : orders) {
            List<HabitOrderRelate> relates = findIndateRelateForOrder(o.getId());

            // 累计清单内打卡数量
            int clockInDateCount = 0;

            List<HabitAndOrderVo> temp = new ArrayList<>();
            for (HabitOrderRelate r : relates) {
                Habit h = habitMap.get(r.getHid());
                if (h == null) {
                    continue;
                }

                HabitAndOrderVo habitVo = new HabitAndOrderVo();
                habitVo.setOrderId(r.getOrderId());
                habitVo.setRelateId(r.getId());
                habitVo.setHabitId(r.getHid());
                habitVo.setHabitTitle(h.getTitle());
                habitVo.setHabitSubTitle(h.getDesc());
                habitVo.setHabitPreMinute(h.getPreMinute());
                habitVo.setHabitEmoji(getRandomImg());
                habitVo.setQuadrant(h.getQuadrant());


                // 获取打卡事件(含事件的才显现在列表中)
                HabitEvent event = getHabitEventForDay(r.getId(), new Date());
                if (event != null) {

                    habitVo.setEventId(event.getId());
                    if (event.getFinish()) {
                        habitVo.setEventFinish(event.getFinish());
                        habitVo.setEventClockInDate(event.getClockInDate());

                        // 统计打卡数量（目标/已完成）
                        habitVo.setEventTotalCount(countHabitEvent(r.getId()));
                        habitVo.setEventFinishCount(countHabitEventFinish(r.getId()));

                        clockInDateCount++;
                    }

                    // 隐藏已完成项
                    if (spHideFinish && !habitVo.isEventFinish()) {
                        temp.add(habitVo);
                    } else if (!spHideFinish) {
                        temp.add(habitVo);
                    }
                }
            }

            HabitAndOrderVo orderVo = convertHabitAndOrderVoForGroup(o);
            // 全部完成
            if (clockInDateCount != 0 && clockInDateCount == relates.size()) {
                orderVo.setOrderFinish(true);
            }

            // 隐藏已完成项
            if (spHideFinish && !orderVo.isOrderFinish()) {
                result.add(orderVo);
            } else if (!spHideFinish) {
                result.add(orderVo);
            }

            // 添加明细(按优先级排序)
            Collections.sort(temp, new QuadrantAscComparetor());
            result.addAll(temp);
        }
        return result;
    }

    public static class QuadrantAscComparetor implements Comparator<HabitAndOrderVo> {
        @Override
        public int compare(HabitAndOrderVo lhs, HabitAndOrderVo rhs) {
            if (lhs.getQuadrant() > rhs.getQuadrant()) {
                return 1;
            } else if (lhs.getQuadrant() < rhs.getQuadrant()) {
                return -1;
            } else {
                return 0;
            }
        }
    }


    public List<HabitItemVo> findHabitItemVoForOrder(Long orderId, int sortType, String searchKey) {
        List<HabitItemVo> result = new ArrayList<>();
        List<Habit> hList;

        List<HabitOrderRelate> rList = findIndateRelateForOrder(orderId);

        // 可用范围（未加入清单的习惯项）的习惯项
        List<Long> unJoinOrderHabitIds = findHabitIdForUnJoinOrder(orderId);
        if (!TextUtils.isEmpty(searchKey)) {
            hList = new ArrayList<>();
            // 通过关键字查询习惯项
            for (Habit h : findHabit(searchKey)) {
                // 匹配是否在可用范围（未加入清单的习惯项）
                if (unJoinOrderHabitIds.contains(h.getId())) {
                    hList.add(h);
                }
            }
        } else {
            hList = findHabits(unJoinOrderHabitIds);
        }

        hList.forEach(n -> {
            HabitItemVo v = new HabitItemVo();

            v.setEmoji(getRandomImg());
            v.setId(n.getId());
            v.setTitle(n.getTitle());
            v.setPreMinute(n.getPreMinute());
            v.setSubTitle(n.getDesc());
            v.setOrderId(orderId);
            v.setQuadrant(n.getQuadrant());

            for (HabitOrderRelate r : rList) {
                if (r.getHid().equals(n.getId())) {
                    v.setJoin(true);
                    v.setRelateId(r.getId());
                }
            }

            // 0 全部；1已选；2未选
            if (sortType == 1 && v.isJoin()) {
                result.add(v);
            } else if (sortType == 2 && !v.isJoin()) {
                result.add(v);
            } else if (sortType == 0) {
                result.add(v);
            }

        });

        // 排序
        if (sortType == 0) {
            Collections.sort(result, new Comparator<HabitItemVo>() {
                @Override
                public int compare(HabitItemVo o1, HabitItemVo o2) {
                    if (o1.isJoin() == o2.isJoin()) {
                        return 0;
                    } else if (o1.isJoin()) {
                        return -1;
                    } else if (o2.isJoin()) {
                        return 1;
                    }
                    return 0;
                }
            });
        }

        return result;
    }


    public HabitAndOrderVo convertHabitAndOrderVoForGroup(HabitOrder o) {
        return new HabitAndOrderVo(o.getId(), o.getTitle(), false);
    }

    public HabitAndOrderVo convertHabitAndOrderVoForGroup(Long id) {
        if (id == null) {
            return null;
        }
        HabitOrder o = getHabitOrderDao().load(id);
        return new HabitAndOrderVo(o.getId(), o.getTitle(), false);
    }

    private int getRandomImg() {
        return habitEmojiArray[random.nextInt(habitEmojiArray.length)];
    }

    public List<HabitOrder> findOrder() {
        return getHabitOrderDao().queryBuilder()
                .where(HabitOrderDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .orderAsc(HabitOrderDao.Properties.StartTime)
                .list();
    }

    public boolean existOrderName(String key) {
        List<HabitOrder> list = getHabitOrderDao().queryBuilder()
                .where(HabitOrderDao.Properties.Title.eq(key))
                .where(HabitOrderDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .list();
        return list != null && list.size() > 0;
    }

    public boolean existOrderRelate(Long hid) {
        List<HabitOrderRelate> list = getHabitOrderRelateDao().queryBuilder()
                .where(HabitOrderRelateDao.Properties.Hid.eq(hid))
                .where(HabitOrderRelateDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .list();
        return list != null && list.size() > 0;
    }

    public boolean existHabitName(String key) {
        List<Habit> list = getHabitDao().queryBuilder()
                .where(HabitDao.Properties.Title.eq(key))
                .where(HabitDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .list();
        return list != null && list.size() > 0;
    }

    public List<HabitOrderRelate> findAllOrderRelate() {
        return getHabitOrderRelateDao().queryBuilder()
                .where(HabitOrderRelateDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .orderAsc(HabitOrderRelateDao.Properties.Sort)
                .list();
    }

    public List<HabitOrderRelate> findRelateForOrder(Long oid) {
        return getHabitOrderRelateDao().queryBuilder()
                .where(HabitOrderRelateDao.Properties.OrderId.eq(oid))
                .where(HabitOrderRelateDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .orderAsc(HabitOrderRelateDao.Properties.Sort)
                .list();
    }

    public List<Habit> findHabitForUnJoinOrder(Long orderId) {
        List<Long> idList = findHabitIdForUnJoinOrder(orderId);
        return getHabitDao().queryBuilder()
                .where(HabitDao.Properties.Id.in(idList))
                .list();
    }

    private List<Habit> findHabits(List<Long> idList) {
        return getHabitDao().queryBuilder()
                .where(HabitDao.Properties.Id.in(idList))
                .list();
    }

    private List<Long> findHabitIdForUnJoinOrder(Long orderId) {
        // 查询未加入至清单的习惯

        // 所有项
        BitSet habitSet = new BitSet();
        Iterator<Habit> habitIterator = getHabitDao().loadAll().iterator();
        while (habitIterator.hasNext()) {
            habitSet.set(habitIterator.next().getId().intValue());
        }

        // 已使用项(不含指定清单)
        BitSet habitUnJoinSet = new BitSet();
        List<HabitOrderRelate> relates = getHabitOrderRelateDao().queryBuilder()
                .where(HabitOrderRelateDao.Properties.OrderId.notEq(orderId))
                //2019-04-02 <= 2019-04-02 23:59:59
                .where(HabitOrderRelateDao.Properties.BeginDt.le(DateUtils.setEndTime(new Date())))
                //2019-04-02 <= 2019-04-02 00:00:00
                .where(HabitOrderRelateDao.Properties.EndDt.ge(DateUtils.setStartTime(new Date())))
                .where(HabitOrderRelateDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .orderAsc(HabitOrderRelateDao.Properties.Sort)
                .list();
        Iterator<HabitOrderRelate> relateIterator = relates.iterator();
        while (relateIterator.hasNext()) {
            habitUnJoinSet.set(relateIterator.next().getHid().intValue());
        }

        // 未使用项
        habitUnJoinSet.xor(habitSet);

        return habitUnJoinSet.stream().asLongStream().boxed().collect(Collectors.toList());
    }

    public List<HabitOrderRelate> findIndateRelateForOrder(Long oid) {
        return getHabitOrderRelateDao().queryBuilder()
                .where(HabitOrderRelateDao.Properties.OrderId.eq(oid))
                //2019-04-02 <= 2019-04-02 23:59:59
                .where(HabitOrderRelateDao.Properties.BeginDt.le(DateUtils.setEndTime(new Date())))
                //2019-04-02 <= 2019-04-02 00:00:00
                .where(HabitOrderRelateDao.Properties.EndDt.ge(DateUtils.setStartTime(new Date())))
                .where(HabitOrderRelateDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .orderAsc(HabitOrderRelateDao.Properties.CreatedDt)
                .list();
    }

    public List<HabitEvent> findHabitEventForOrder(Long oid) {
        return getHabitEventDao().queryBuilder()
                .where(HabitEventDao.Properties.Oid.eq(oid))
                .orderAsc(HabitEventDao.Properties.CreatedDt)
                .list();
    }

    public List<HabitEvent> findHabitEventForRelate(Long rid) {
        return getHabitEventDao().queryBuilder()
                .where(HabitEventDao.Properties.Rid.eq(rid))
                .orderAsc(HabitEventDao.Properties.ScheduleDt)
                .list();
    }

    public List<HabitEvent> findHabitEvent(Long hid) {
        return getHabitEventDao().queryBuilder()
                .where(HabitEventDao.Properties.Hid.eq(hid))
                .orderAsc(HabitEventDao.Properties.ScheduleDt)
                .list();
    }

    public HabitEvent getHabitEventForDay(Long rid, Date date) {
        List<HabitEvent> events = getHabitEventDao().queryBuilder()
                .where(HabitEventDao.Properties.Rid.eq(rid))
                // 2019-01-11 >= 2019-01-11 00:00:00
                .where(HabitEventDao.Properties.ScheduleDt.ge(DateUtils.setStartTime(date)))
                // 2019-01-11 <= 2019-01-11 23:59:59
                .where(HabitEventDao.Properties.ScheduleDt.le(DateUtils.setEndTime(date)))
                .list();
        if (events != null && events.size() > 0) {
            return events.get(0);
        }
        return null;
    }

    public int countHabitEvent(Long rid) {
        return (int) getHabitEventDao().queryBuilder()
                .where(HabitEventDao.Properties.Rid.eq(rid))
                .count();
    }

    public int countHabitEventFinish(Long rid) {
        return (int) getHabitEventDao().queryBuilder()
                .where(HabitEventDao.Properties.Rid.eq(rid))
                .where(HabitEventDao.Properties.Finish.eq(true))
                .count();
    }

    public List<HabitOrderRelate> findOrderRelate(Long oid, Long hid) {
        return getHabitOrderRelateDao().queryBuilder()
                .where(HabitOrderRelateDao.Properties.OrderId.eq(oid))
                .where(HabitOrderRelateDao.Properties.Hid.eq(hid))
                .where(HabitOrderRelateDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .orderAsc(HabitOrderRelateDao.Properties.Sort)
                .list();
    }

    public HabitOrderRelate existRelateAndReturn(Long oid, Long hid) {
        List<HabitOrderRelate> list = findOrderRelate(oid, hid);

        // 查询有效期内（若过期则进入不了此场景）
        /*List<HabitOrderRelate> list = getHabitOrderRelateDao().queryBuilder()
                .where(HabitOrderRelateDao.Properties.OrderId.eq(oid))
                .where(HabitOrderRelateDao.Properties.Hid.eq(hid))
                //2019-04-02 <= 2019-04-02 23:59:59
                .where(HabitOrderRelateDao.Properties.BeginDt.le(DateUtils.setEndTime(new Date())))
                //2019-04-02 <= 2019-04-02 00:00:00
                .where(HabitOrderRelateDao.Properties.EndDt.ge(DateUtils.setStartTime(new Date())))
                .where(HabitOrderRelateDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .orderAsc(HabitOrderRelateDao.Properties.Sort)
                .list();*/

        if (list != null && list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    public boolean isHabitJoin(Long hid) {
        return getHabitOrderRelateDao().queryBuilder()
                .where(HabitOrderRelateDao.Properties.Hid.eq(hid))
                .where(HabitOrderRelateDao.Properties.Status.eq(AppStatus.Status.NORMAL))
                .orderAsc(HabitOrderRelateDao.Properties.Sort)
                .list().size() > 0;
    }

    public HabitEvent doClockInDate(Long rid) {
        // 当天打卡
        HabitEvent e = getHabitEventForDay(rid, new Date());
        if (e == null) {
            return null;
        }

        if (!e.getFinish()) {
            e.setFinish(true);
            e.setClockInDate(new Date());
            e.setUpdatedDt(e.getClockInDate());
            getHabitEventDao().save(e);
        }
        return e;
    }

    public HabitEvent doClockInDateForHabitEvent(Long eid) {
        // 指定日期打卡
        HabitEvent e = getHabitEventDao().load(eid);
        if (e == null) {
            return null;
        }

        if (!e.getFinish()) {
            e.setFinish(true);
            e.setClockInDate(new Date());
            e.setUpdatedDt(e.getClockInDate());
            getHabitEventDao().save(e);
        }
        return e;
    }

    public Integer[] findClockInDate(Long rid) {
        Integer[] arr = new Integer[2];
        arr[0] = countHabitEvent(rid);
        arr[1] = countHabitEventFinish(rid);
        return arr;
    }

    public void doUnfinish(Long logId) {
        if (logId == null) {
            return;
        }
        HabitEvent e = getHabitEventDao().load(logId);
        e.setFinish(false);
        e.setClockInDate(null);
        e.setUpdatedDt(new Date());
        getHabitEventDao().save(e);
    }

    public HabitOrderRelate doJoin(Long oid, Long hid) {
        HabitOrder o = getHabitOrderDao().load(oid);
        Habit h = getHabitDao().load(hid);
        if (o == null || h == null) {
            return null;
        }

        // 在有效期内存在则直接返回
        HabitOrderRelate exist = existRelateAndReturn(oid, hid);
        if (exist != null) {
            return exist;
        }

        // 创建新关联
        HabitOrderRelate r = getDefaultHabitOrderRelate(hid, oid);
        getHabitOrderRelateDao().save(r);

        // 创建关联事件
        createHabitEvent(r);

        return r;
    }

    public void doRmoveJoin(Long rid) {
        // 删除打卡日志
        delHabitEvent(rid);

        getHabitOrderRelateDao().deleteByKey(rid);
    }

    private void delHabitEvent(Long rid) {
        // 清空已有事件(只清楚未打卡事件，已打卡事件依然保留)
        List<HabitEvent> events = getHabitEventDao().queryBuilder()
                .where(HabitEventDao.Properties.Rid.eq(rid))
                .where(HabitEventDao.Properties.Finish.notEq(true))
                .list();


        // 删除关联的备注信息
        BitSet delId = new BitSet();
        Iterator<HabitEvent> iterator = events.iterator();
        while (iterator.hasNext()) {
            delId.set(iterator.next().getId().intValue());
        }
        List<Remark> remarks = getRemarkDao().queryBuilder()
                .where(RemarkDao.Properties.RelateId.in(delId))
                .where(RemarkDao.Properties.RelateType.eq(AppStatus.RemarkType.HABIT_SIGNIN))
                .list();
        getRemarkDao().deleteInTx(remarks);

        getHabitEventDao().deleteInTx(events);
    }

    private void delHabitEventForOrderDel(Long oid) {
        // 清空已有事件(只清楚未打卡事件，已打卡事件依然保留)
        List<HabitEvent> events = getHabitEventDao().queryBuilder()
                .where(HabitEventDao.Properties.Oid.eq(oid))
                .where(HabitEventDao.Properties.Finish.notEq(true))
                .list();


        // 删除关联的备注信息
        BitSet delId = new BitSet();
        Iterator<HabitEvent> iterator = events.iterator();
        while (iterator.hasNext()) {
            delId.set(iterator.next().getId().intValue());
        }
        List<Remark> remarks = getRemarkDao().queryBuilder()
                .where(RemarkDao.Properties.RelateId.in(delId))
                .where(RemarkDao.Properties.RelateType.eq(AppStatus.RemarkType.HABIT_SIGNIN))
                .list();
        getRemarkDao().deleteInTx(remarks);

        getHabitEventDao().deleteInTx(events);
    }


    public List<Habit> findHabit(String searchKey) {
        QueryBuilder<Habit> q = getHabitDao().queryBuilder();
        if (!TextUtils.isEmpty(searchKey)) {
            q.where(HabitDao.Properties.Title.like("%" + searchKey + "%"));
        }
        q.where(HabitDao.Properties.Status.eq(AppStatus.Status.NORMAL));
        q.orderAsc(HabitDao.Properties.Quadrant);
        q.orderAsc(HabitDao.Properties.Title);
        return q.list();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    public Map<Long, Habit> findAllHabit2Map() {
        Map<Long, Habit> result = new HashMap<>();
        List<Habit> data = findHabit(null);
        data.forEach(h -> {
            if (h != null) {
                result.put(h.getId(), h);
            }
        });
        return result;
    }

    public List<HabitVo> findAllForManage() {
        List<HabitVo> result = new ArrayList<>();

        for (Habit t : findHabit(null)) {
            result.add(convertManage(t));
        }
        return result;
    }

    public HabitVo getHabitVo(Long id) {
        return convertManage(getHabitDao().load(id));
    }

    public Habit saveHabit(Habit target) {
        Habit source = null;
        if (target.getId() == null || target.getId() == 0) {
            source = getDefaultHabit();
        } else {
            source = getHabitDao().load(target.getId());
        }
        if (source == null) {
            return null;
        }

        source.setTitle(target.getTitle());
        source.setDesc(target.getDesc());
        source.setPreMinute(target.getPreMinute());
        source.setUpdatedDt(new Date());
        getHabitDao().save(source);
        return source;
    }

    public HabitOrder saveHabitOrder(HabitOrder target) {
        HabitOrder source = null;
        if (target.getId() == null || target.getId() == 0) {
            source = getDefaultHabitOrder();
        } else {
            source = getHabitOrderDao().load(target.getId());
        }
        if (source == null) {
            return null;
        }

        source.setTitle(target.getTitle());
        source.setStartTime(target.getStartTime());
        source.setEndTime(target.getEndTime());
        source.setOpenRemind(target.getOpenRemind());
        source.setRemindInterval(target.getRemindInterval());
        source.setSort(target.getSort());
        source.setUpdatedDt(new Date());
        getHabitOrderDao().save(source);
        return source;
    }

    public HabitOrderRelate saveHabitOrderRelate(HabitOrderRelate r) {
        // 保存修改项
        r.setUpdatedDt(new Date());
        getHabitOrderRelateDao().save(r);

        // 删除无效事件
        delHabitEvent(r.getId());

        // 创建新事件
        createHabitEvent(r);

        return r;
    }


    public void createHabitEvent(HabitOrderRelate r) {

        // 将已打卡数据查询出来，避免重复生成
        List<String> existDate = new ArrayList<>();
        List<HabitEvent> events = getHabitEventDao().queryBuilder()
                .where(HabitEventDao.Properties.Hid.eq(r.getHid()))
                .where(HabitEventDao.Properties.Finish.eq(true))
                .list();
        Iterator<HabitEvent> iterator = events.iterator();
        while (iterator.hasNext()) {
            existDate.add(DateUtils.date2str(iterator.next().getScheduleDt(), DateUtils.F41));
        }


        // 生成区间内所有日期
        List<Date> dates = DateUtils.findDates(r.getBeginDt(), r.getEndDt());
        for (Date date : dates) {

            // 指定日期中如已存在打卡数据则沿用之前的
            if (existDate.size() > 0) {
                if (existDate.contains(DateUtils.date2str(date, DateUtils.F41))) {
                    continue;
                }
            }

            switch (r.getRepeatType()) {
                case AppStatus.RepeatType.EVERYMONTH:
                    // 每月
                    int day = DateUtils.getDay(date);
                    if (day != r.getRepeatFirst()) {
                        // 当设定日期超过当月最后一天时使用最后一天
                        if (day > 27 && day < r.getRepeatFirst()) {
                            int lastDay = DateUtils.getDay(DateUtils.getLastDayOfMonth2Date(DateUtils.getYear(date), DateUtils.getMoth(date)));
                            if (day != lastDay) {
                                continue;
                            }
                        } else {
                            continue;
                        }
                    }
                    break;
                case AppStatus.RepeatType.EVERYWEEK:
                    if (DateUtils.getWeek(date) != r.getRepeatFirst()) {
                        continue;// 每周
                    }
                    break;
                case AppStatus.RepeatType.WORKDAY:
                    if ((DateUtils.getWeek(date) == 0 || DateUtils.getWeek(date) == 6)) {
                        continue;// 工作日（含法定假日）
                    }
                    break;
                case AppStatus.RepeatType.UNWORKDAY:
                    if (DateUtils.getWeek(date) != 0 && DateUtils.getWeek(date) != 6) {
                        continue;// 非工作日（不含法定假日）
                    }
                    break;
            }

            HabitEvent e = getDefaultHabitEvent(r, date, DateUtils.getYearWeekNumber(date));
            getHabitEventDao().save(e);
        }
    }


    public void delHabit(Long id) {
        Habit t = getHabitDao().load(id);
        if (t == null) {
            return;
        }

        t.setStatus(AppStatus.Status.DEL);
        t.setUpdatedDt(new Date());
        getHabitDao().save(t);
    }

    private HabitVo convertManage(Habit t) {
        HabitVo v = new HabitVo();

        v.setId(t.getId());
        v.setEmojiResId(getRandomImg());
        v.setTitle(t.getTitle());
        v.setSubtitle(t.getDesc());
        v.setMinute(t.getPreMinute());
        v.setQuadrant(t.getQuadrant());
        return v;
    }


    public Habit getDefaultHabit() {
        Habit t = new Habit();
        t.setTitle("");
        t.setDesc("");
        t.setEmojiPath(null);
        t.setPreMinute(15);
        t.setQuadrant(AppStatus.Quadrant.FOUR);
        t.setStatus(AppStatus.Status.NORMAL);
        t.setCreatedDt(new Date());
        t.setUpdatedDt(new Date());
        return t;
    }


    public HabitEvent getDefaultHabitEvent(HabitOrderRelate r, Date scheduleDt, Integer scheduleWeekNum) {
        HabitEvent t = new HabitEvent();
        t.setRid(r.getId());
        t.setHid(r.getHid());
        t.setOid(r.getOrderId());
        t.setScheduleWeekNum(scheduleWeekNum);
        t.setScheduleDt(scheduleDt);
        t.setCreatedDt(new Date());
        t.setUpdatedDt(t.getCreatedDt());
        t.setFinish(false);
        t.setClockInDate(null);
        return t;
    }

    public HabitOrder getDefaultHabitOrder() {
        HabitOrder t = new HabitOrder();
        t.setTitle("习惯清单");
        t.setStartTime(DateUtils.setTime(new Date(), 9, 0, 0, 0));
        t.setEndTime(DateUtils.setTime(new Date(), 18, 0, 0, 0));
        t.setOpenRemind(false);
        t.setRemindInterval(10);
        t.setSort(1);
        t.setStatus(AppStatus.Status.NORMAL);
        t.setCreatedDt(new Date());
        t.setUpdatedDt(new Date());
        return t;
    }

    public HabitOrderRelate getDefaultHabitOrderRelate(long hid, long oid) {
        HabitOrderRelate t = new HabitOrderRelate();
        t.setHid(hid);
        t.setOrderId(oid);
        t.setBeginDt(new Date());
        t.setEndDt(DateUtils.moveDay(t.getBeginDt(), 90));
        t.setRepeatType(AppStatus.RepeatType.EVERYDAY);
        t.setSort(1);
        t.setStatus(AppStatus.Status.NORMAL);
        t.setCreatedDt(new Date());
        t.setUpdatedDt(t.getCreatedDt());
        return t;
    }

    public HabitOrderVo getHabitAndOrderVo(long id) {
        if (id == 0) {
            return null;
        }
        return HabitOrderVo.convert(getHabitOrderDao().load(id));
    }

    public void delHabitOrder(Long oid) {
        if (oid == null || oid == 0) {
            return;
        }
        HabitOrder o = getHabitOrderDao().load(oid);
        if (o == null) {
            return;
        }

        // 关联
        List<HabitOrderRelate> rList = findRelateForOrder(oid);
        getHabitOrderRelateDao().deleteInTx(rList);

        // 打卡日志
        delHabitEventForOrderDel(oid);

        getHabitOrderDao().delete(o);
    }

    public void saveQuadrant(Long id, Integer quadrant) {
        if (id == null) {
            return;
        }
        getTaskDao().detachAll();
        Habit t = getHabitDao().load(id);
        if (t != null && !t.getQuadrant().equals(quadrant)) {
            t.setQuadrant(quadrant);
            t.setUpdatedDt(new Date());
            getHabitDao().save(t);
            getTaskDao().detachAll();
        }
    }

}
